home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1997
/
HAM Radio 1997.iso
/
vcls
/
sockv2
/
sockets.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-04-08
|
46KB
|
1,308 lines
unit Sockets;
{ Install this component using Options|Install Compenents.
The function of this module is to provide Delphi with a
component capable of performing TCP/IP Socket's functions
by interfacing with WINSOCK.DLL provided by many vendors
including Microsoft.
The code herein is released to the public domain under the condition
that it will not be used for commercial or "For Profit" ventures.
Written By: Gary T. Desrosiers
Date: March 27th, 1995.
Copyright: (R) Copyright by Gary T. Desrosiers, 1995. All Rights Reserved
UserID(s): 71062,2754
desrosi@pcnet.com
Description: This control performs WinSock TCP/IP functions.
Prerequisites: You will need a WinSock 1.1 compatable TCP/IP stacks
to use this control. The control has been tested with
Trumpet 2.1B, Chameleon 4.03, PC/TCP, and the native
stacks in Windows NT and Windows 95.
Modifications: Version 2 - July 5th, 1995
- Added properties;
- MasterSocket, Gets the listener's socket
- Peek, Preview data in the input buffer.
- NonBlocking, Blocking vs Non-Blocking sockets
- Timeout, For blocking mode timeouts
- OOB, Sends and receives data out of band (urgent data)
- Modified properties;
- SocketNumber to read/write
- Text (no longer published)
- Added Methods;
- SCancelListen, new method cancels the listener socket
- GetPeerIPAddr, returns partners IP address
- GetPeerPort, returns partners port
- Modified Methods;
- GetIPAddr, Documented and bug fix
- GetPort, Documented
- SClose, Added shutdown, etc.
- SReceive, Modified to use PChar instead of Pascal strings
- SSend, Modified to use PChar instead of Pascal strings
- SetText, Now loops until entire buffer sent
- Added Events
- OnErrorOccurred, Called on WinSock errors.
Properties: IPAddr, Design time and runtime read/write.
Sets the IP Address of the partner that you will
eventually SConnect to. You may specify this as
dotted decimal or a literal name to be converted
via DNS.
examples;
Sockets1.IPAddr := 'desrosi';
Sockets1.IPAddr := '127.0.0.1';
addr := Sockets1.IPAddr;
Port, Design time and runtime read/write.
Sets the Port number of the remote port to connect
to or the local port to listen on depending on
whether you subsequently issue a SConnect or SListen.
This can be specified as a number or a literal name
to be converted via DNS.
examples;
Sockets1.Port := 'echo';
Sockets1.Port := '7';
port := Sockets1.Port;
SocketNumber, Runtime Read/write.
Returns (or sets) the socket number of the currently
allocated connection.
example;
sock := Sockets1.SocketNumber;
MasterSocket, Runtime Read/Write.
Returns (or sets) the master socket number (listener)
example;
msock := Sockets1.MasterSocket;
Text, Design time and runtime read/write.
if set, sends the text to the partner.
if read, receives some text from the partner.
examples;
buffer := Sockets1.Text; (* Receive data *)
Sockets1.Text := 'This is a test'; (* Send Data *)
Peek, runtime read only.
Returns up to 255 characters of data waiting to
be received but does not actually receive the
data.
OOB, runtime read/write.
if set, sends the text to the partner as urgent (out of
band) data.
if read, receives urgent (out of band) data.
examples;
buffer := Sockets1.OOB;
Sockets1.OOB := 'This is a test';
NonBlocking, Design time and runtime read/write
Set to False for blocking mode and True for non-blocking
mode (the default). When the socket is in blocking
mode, none of the event callback functions (with the
exception of OnErrorOccurred) will function.
Timeout, Design time and runtime read/write
When NonBlocking = 0 (blocking mode) this value
specifies the maximum amount of time that
a socket operation can take. After this time
limit expires, the operation is canceled and
an error occurs. The default is 30 (seconds).
The Valid range is 0-60 seconds. Setting Timeout
to zero causes the operation to wait indefinitely.
Methods: SConnect - Connects to the remote (or local) system
specified in the IPAddr and Port properties.
example;
Sockets1.SConnect; (* Connect to partner *)
SListen - Listens on the port specified in the Port
property.
example;
Sockets1.SListen; (* Establish server environment *)
SCancelListen - Cancels listens on the socket.
example;
Sockets1.SCancelListen; (* Dont accept further clients *)
SAccept - Accepts a client request. Usually issued in
OnSessionAvailable event.
example;
Sock := Sockets1.SAccept; (* Get client connection *)
SClose - Closes the socket.
example;
Sockets1.SClose; (* Close connection *)
SReceive - Receives data from partner, similar to
reading the property Text although this function
uses PChar instead of Pascal strings.
example;
len := Sockets1.SReceive(Sockets1.SocketNumber,szBuffer,4096);
SSend - Sends data to the partner, similar to
setting the property Text although this function
uses PChar instead of Pascal strings.
example;
len := Sockets1.SSend(Sockets1.SocketNumber,szBuff,32000);
GetPort - Returns the actual port number of the socket
specified as the argument. Generally used when you've
specified a port of zero and need to retrieve the
assigned port number.
GetIPAddr - Returns the IP Address of the socket specified
as the argument.
GetPeerPort - Returns the partners port number of the socket
specified as the argument.
GetPeerIPAddr - Returns partners IP Address of the socket
specified as the argument.
Events: OnDataAvailable - Called when data is available to
be received from the partner. You should issue;
buffer := Sockets1.Text; or a SReceive method to
receive the data from the partner.
OnSessionAvailable - Called when a client has requested
to connect to a 'listening' server. You can call
the method SAccept here.
OnSessionClosed - Called when the partner has closed
a socket on you. Normally, you would close your side
of the socket when this event happens.
OnSessionConnected - Called when the SConnect has
completed and the session is connected. This is a
good place to send the initial data of a conversation.
Also, you may want to enable certain controls that
allow the user to send data on the conversation here.
OnErrorOccurred - Called when an error occurs on the socket.
If defined, the OnErrorOccurred procedure is called when
the error occurs. If the procedure isn't defined then
a dialog box is displayed with the error text and the
program is halted.
}
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs;
const
{ Not all of these constants are used in this component, I included
the entire WinSock.h header file constants for completeness. }
{ User Windows Messages }
WM_ASYNCSELECT = WM_USER + 0;
{ Misc constants }
FD_SETSIZE = 64;
INADDR_ANY: longint = 0;
INADDR_NONE: longint = -1;
INADDR_LOOPBACK: longint = $7f000001; { IPAddr: 127.0.0.1 }
WSADESCRIPTION_LEN = 256;
WSASYS_STATUS_LEN = 128;
{ Protocols }
IPPROTO_IP = 0; { dummy for IP }
IPPROTO_ICMP = 1; { control message protocol }
IPPROTO_GGP = 2; { gateway^2 (deprecated) }
IPPROTO_TCP = 6; { tcp }
IPPROTO_PUP = 12; { pup }
IPPROTO_UDP = 17; { user datagram protocol }
IPPROTO_IDP = 22; { xns idp }
IPPROTO_ND = 77; { UNOFFICIAL net disk proto }
IPPROTO_RAW = 255; { raw IP packet }
IPPROTO_MAX = 256;
{ Port/socket numbers: network standard functions }
IPPORT_ECHO = 7;
IPPORT_DISCARD = 9;
IPPORT_SYSTAT = 11;
IPPORT_DAYTIME = 13;
IPPORT_NETSTAT = 15;
IPPORT_FTP = 21;
IPPORT_TELNET = 23;
IPPORT_SMTP = 25;
IPPORT_TIMESERVER = 37;
IPPORT_NAMESERVER = 42;
IPPORT_WHOIS = 43;
IPPORT_MTP = 57;
{ Port/socket numbers: host specific functions }
IPPORT_TFTP = 69;
IPPORT_RJE = 77;
IPPORT_FINGER = 79;
IPPORT_TTYLINK = 87;
IPPORT_SUPDUP = 95;
{ UNIX TCP sockets }
IPPORT_EXECSERVER = 512;
IPPORT_LOGINSERVER = 513;
IPPORT_CMDSERVER = 514;
IPPORT_EFSSERVER = 520;
{ UNIX UDP sockets }
IPPORT_BIFFUDP = 512;
IPPORT_WHOSERVER = 513;
IPPORT_ROUTESERVER = 520;
{ Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root) }
IPPORT_RESERVED = 1024;
{ Link numbers }
IMPLINK_IP = 155;
IMPLINK_LOWEXPER = 156;
IMPLINK_HIGHEXPER = 158;
INVALID_SOCKET = $ffff;
SOCKET_ERROR = (-1);
{ Types }
SOCK_STREAM = 1; { stream socket }
SOCK_DGRAM = 2; { datagram socket }
SOCK_RAW = 3; { raw-protocol interface }
SOCK_RDM = 4; { reliably-delivered message }
SOCK_SEQPACKET = 5; { sequenced packet stream }
{ Option flags per-socket }
SO_DEBUG = $0001; { turn on debugging info recording }
SO_ACCEPTCONN = $0002; { socket has had listen() }
SO_REUSEADDR = $0004; { allow local address reuse }
SO_KEEPALIVE = $0008; { keep connections alive }
SO_DONTROUTE = $0010; { just use interface addresses }
SO_BROADCAST = $0020; { permit sending of broadcast msgs }
SO_USELOOPBACK = $0040; { bypass hardware when possible }
SO_LINGER = $0080; { linger on close if data present }
SO_OOBINLINE = $0100; { leave received OOB data in line }
SO_DONTLINGER = (not SO_LINGER);
{ Additional options }
SO_SNDBUF = $1001; { send buffer size }
SO_RCVBUF = $1002; { receive buffer size }
SO_SNDLOWAT = $1003; { send low-water mark }
SO_RCVLOWAT = $1004; { receive low-water mark }
SO_SNDTIMEO = $1005; { send timeout }
SO_RCVTIMEO = $1006; { receive timeout }
SO_ERROR = $1007; { get error status and clear }
SO_TYPE = $1008; { get socket type }
{ TCP options }
TCP_NODELAY = $0001;
{ Address families }
AF_UNSPEC = 0; { unspecified }
AF_UNIX = 1; { local to host (pipes, portals) }
AF_INET = 2; { internetwork: UDP, TCP, etc. }
AF_IMPLINK = 3; { arpanet imp addresses }
AF_PUP = 4; { pup protocols: e.g. BSP }
AF_CHAOS = 5; { mit CHAOS protocols }
AF_NS = 6; { XEROX NS protocols }
AF_ISO = 7; { ISO protocols }
AF_OSI = AF_ISO; { OSI is ISO }
AF_ECMA = 8; { european computer manufacturers }
AF_DATAKIT = 9; { datakit protocols }
AF_CCITT = 10; { CCITT protocols, X.25 etc }
AF_SNA = 11; { IBM SNA }
AF_DECnet = 12; { DECnet }
AF_DLI = 13; { Direct data link interface }
AF_LAT = 14; { LAT }
AF_HYLINK = 15; { NSC Hyperchannel }
AF_APPLETALK = 16; { AppleTalk }
AF_NETBIOS = 17; { NetBios-style addresses }
AF_MAX = 18;
{ Protocol families, same as address families for now }
PF_UNSPEC = AF_UNSPEC;
PF_UNIX = AF_UNIX;
PF_INET = AF_INET;
PF_IMPLINK = AF_IMPLINK;
PF_PUP = AF_PUP;
PF_CHAOS = AF_CHAOS;
PF_NS = AF_NS;
PF_ISO = AF_ISO;
PF_OSI = AF_OSI;
PF_ECMA = AF_ECMA;
PF_DATAKIT = AF_DATAKIT;
PF_CCITT = AF_CCITT;
PF_SNA = AF_SNA;
PF_DECnet = AF_DECnet;
PF_DLI = AF_DLI;
PF_LAT = AF_LAT;
PF_HYLINK = AF_HYLINK;
PF_APPLETALK = AF_APPLETALK;
PF_MAX = AF_MAX;
{ Level number for (get/set)sockopt() to apply to socket itself }
SOL_SOCKET = -1; { options for socket level }
{ Maximum queue length specifiable by listen }
SOMAXCONN = 5;
MSG_OOB = $1; { process out-of-band data }
MSG_PEEK = $2; { peek at incoming message }
MSG_DONTROUTE = $4; { send without using routing tables }
MSG_MAXIOVLEN = 16;
{ Define constant based on rfc883, used by gethostbyxxxx() calls }
MAXGETHOSTSTRUCT = 1024;
{ Define flags to be used with the WSAAsyncSelect() call }
FD_READ = $01;
FD_WRITE = $02;
FD_OOB = $04;
FD_ACCEPT = $08;
FD_CONNECT = $10;
FD_CLOSE = $20;
{ All Windows Sockets error constants are biased by WSABASEERR fromthe normal }
WSABASEERR = 10000;
{ Windows Sockets definitions of regular Microsoft C error constants }
WSAEINTR = (WSABASEERR+4);
WSAEBADF = (WSABASEERR+9);
WSAEACCES = (WSABASEERR+13);
WSAEFAULT = (WSABASEERR+14);
WSAEINVAL = (WSABASEERR+22);
WSAEMFILE = (WSABASEERR+24);
{ Windows Sockets definitions of regular Berkeley error constants }
WSAEWOULDBLOCK = (WSABASEERR+35);
WSAEINPROGRESS = (WSABASEERR+36);
WSAEALREADY = (WSABASEERR+37);
WSAENOTSOCK = (WSABASEERR+38);
WSAEDESTADDRREQ = (WSABASEERR+39);
WSAEMSGSIZE = (WSABASEERR+40);
WSAEPROTOTYPE = (WSABASEERR+41);
WSAENOPROTOOPT = (WSABASEERR+42);
WSAEPROTONOSUPPORT = (WSABASEERR+43);
WSAESOCKTNOSUPPORT = (WSABASEERR+44);
WSAEOPNOTSUPP = (WSABASEERR+45);
WSAEPFNOSUPPORT = (WSABASEERR+46);
WSAEAFNOSUPPORT = (WSABASEERR+47);
WSAEADDRINUSE = (WSABASEERR+48);
WSAEADDRNOTAVAIL = (WSABASEERR+49);
WSAENETDOWN = (WSABASEERR+50);
WSAENETUNREACH = (WSABASEERR+51);
WSAENETRESET = (WSABASEERR+52);
WSAECONNABORTED = (WSABASEERR+53);
WSAECONNRESET = (WSABASEERR+54);
WSAENOBUFS = (WSABASEERR+55);
WSAEISCONN = (WSABASEERR+56);
WSAENOTCONN = (WSABASEERR+57);
WSAESHUTDOWN = (WSABASEERR+58);
WSAETOOMANYREFS = (WSABASEERR+59);
WSAETIMEDOUT = (WSABASEERR+60);
WSAECONNREFUSED = (WSABASEERR+61);
WSAELOOP = (WSABASEERR+62);
WSAENAMETOOLONG = (WSABASEERR+63);
WSAEHOSTDOWN = (WSABASEERR+64);
WSAEHOSTUNREACH = (WSABASEERR+65);
WSAENOTEMPTY = (WSABASEERR+66);
WSAEPROCLIM = (WSABASEERR+67);
WSAEUSERS = (WSABASEERR+68);
WSAEDQUOT = (WSABASEERR+69);
WSAESTALE = (WSABASEERR+70);
WSAEREMOTE = (WSABASEERR+71);
{ Extended Windows Sockets error constant definitions }
WSASYSNOTREADY = (WSABASEERR+91);
WSAVERNOTSUPPORTED = (WSABASEERR+92);
WSANOTINITIALISED = (WSABASEERR+93);
{ Authoritative Answer: Host not found }
WSAHOST_NOT_FOUND = (WSABASEERR+1001);
HOST_NOT_FOUND = WSAHOST_NOT_FOUND;
{ Non-Authoritative: Host not found, or SERVERFAIL }
WSATRY_AGAIN = (WSABASEERR+1002);
TRY_AGAIN = WSATRY_AGAIN;
{ Non recoverable errors, FORMERR, REFUSED, NOTIMP }
WSANO_RECOVERY = (WSABASEERR+1003);
NO_RECOVERY = WSANO_RECOVERY;
{ Valid name, no data record of requested type }
WSANO_DATA = (WSABASEERR+1004);
NO_DATA = WSANO_DATA;
{ no address, look for MX record }
WSANO_ADDRESS = WSANO_DATA;
NO_ADDRESS = WSANO_ADDRESS;
{ Windows Sockets errors redefined as regular Berkeley error constants }
EWOULDBLOCK = WSAEWOULDBLOCK;
EINPROGRESS = WSAEINPROGRESS;
EALREADY = WSAEALREADY;
ENOTSOCK = WSAENOTSOCK;
EDESTADDRREQ = WSAEDESTADDRREQ;
EMSGSIZE = WSAEMSGSIZE;
EPROTOTYPE = WSAEPROTOTYPE;
ENOPROTOOPT = WSAENOPROTOOPT;
EPROTONOSUPPORT = WSAEPROTONOSUPPORT;
ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT;
EOPNOTSUPP = WSAEOPNOTSUPP;
EPFNOSUPPORT = WSAEPFNOSUPPORT;
EAFNOSUPPORT = WSAEAFNOSUPPORT;
EADDRINUSE = WSAEADDRINUSE;
EADDRNOTAVAIL = WSAEADDRNOTAVAIL;
ENETDOWN = WSAENETDOWN;
ENETUNREACH = WSAENETUNREACH;
ENETRESET = WSAENETRESET;
ECONNABORTED = WSAECONNABORTED;
ECONNRESET = WSAECONNRESET;
ENOBUFS = WSAENOBUFS;
EISCONN = WSAEISCONN;
ENOTCONN = WSAENOTCONN;
ESHUTDOWN = WSAESHUTDOWN;
ETOOMANYREFS = WSAETOOMANYREFS;
ETIMEDOUT = WSAETIMEDOUT;
ECONNREFUSED = WSAECONNREFUSED;
ELOOP = WSAELOOP;
ENAMETOOLONG = WSAENAMETOOLONG;
EHOSTDOWN = WSAEHOSTDOWN;
EHOSTUNREACH = WSAEHOSTUNREACH;
ENOTEMPTY = WSAENOTEMPTY;
EPROCLIM = WSAEPROCLIM;
EUSERS = WSAEUSERS;
EDQUOT = WSAEDQUOT;
ESTALE = WSAESTALE;
EREMOTE = WSAEREMOTE;
FIONBIO = $8004667E;
FIONREAD = $4004667F;
type
u_char = byte;
u_short = word;
u_int = word;
u_long = longint;
TSocket = u_int;
servent = record
s_name: PChar;
s_aliases: ^PChar;
s_port: integer;
s_proto: PChar;
end;
Pservent = ^servent;
Protoent = record
p_name: PChar;
p_aliases: ^PChar;
p_proto: integer;
end;
Pprotoent = ^protoent;
{ some liberties taken with this structure }
in_addr = record
Case integer of
0: (s_net, s_host, s_lh, s_impno: u_char);
1: (s_w1,s_imp: u_short);
2: (s_addr: u_long);
end;
Pin_addr = ^in_addr;
sockaddr_in = record
sin_family: integer;
sin_port: u_short;
sin_addr: in_addr;
sin_zero: array[0..7] of char;
end;
Psockaddr_in = ^sockaddr_in;
hostent = record
h_name: PChar;
h_aliases: ^PChar;
h_addrtype: word;
h_length: word;
Case integer of
0: (h_addr_list: ^PChar);
1: (h_addr: ^pin_addr);
end;
Phostent = ^hostent;
WSADATA = record
wVersion: word;
wHighVersion: word;
szDescription: array[0..WSADESCRIPTION_LEN] of char;
szSystemStatus: array[0..WSASYS_STATUS_LEN] of char;
iMaxSockets: u_short;
iMaxUdpDg: u_short;
lpVendorInfo: PChar;
end;
sockaddr = record
sa_family: u_short;
sa_data: array[0..13] of char;
end;
sockproto = record
sp_family: u_short;
sp_protocol: u_short;
end;
linger = record
l_onoff: u_short;
l_linger: u_short;
end;
TDataAvailable = procedure (Sender: TObject; Socket: TSocket) of object;
TSessionClosed = procedure (Sender: TObject; Socket: TSocket) of object;
TSessionAvailable = procedure (Sender: TObject; Socket: TSocket) of object;
TSessionConnected = procedure (Sender: TObject; Socket: TSocket) of object;
TErrorOccurred = procedure (Sender: TObject; Error: integer; Msg: string) of object;
TSockets = class(TWinControl)
private
Pse: Pservent;
Phe: Phostent;
Ppe: Pprotoent;
sin: sockaddr_in;
initdata: WSADATA;
FPort: String;
FIPAddr: String;
FSocket: TSocket;
FMSocket: TSocket;
FMode: longint;
FTimeout: integer;
FDataAvailable: TDataAvailable;
FSessionClosed: TSessionClosed;
FSessionAvailable: TSessionAvailable;
FSessionConnected: TSessionConnected;
FErrorOccurred: TErrorOccurred;
procedure SetText(Text: string);
function GetText : string;
procedure SetTextOOB(Text: string);
function GetTextOOB : string;
function PeekData : string;
function SocketErrorDesc(error: integer) : string;
procedure SocketError(sockfunc: string);
procedure TWMPaint(var msg:TWMPaint); message WM_PAINT;
procedure SetTimeout;
procedure ResetTimeout;
protected
procedure WMASyncSelect(var msg: TMessage); message WM_ASYNCSELECT;
procedure WMTimer(var msg: TMessage); message WM_TIMER;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{ I'd like to call these methods Connect, Close, Listen, etc but
they would conflict with the WinSock.DLL function names ! }
procedure SConnect;
procedure SClose;
procedure SListen;
procedure SCancelListen;
function SAccept: TSocket;
function SReceive(aSocket: TSocket; szBuff: PChar; var rlen: integer): integer;
function SSend(aSocket: TSocket;szBuff: PChar; var slen: integer): integer;
function GetIPAddr(aSocket: TSocket): string;
function GetPort(aSocket: TSocket): string;
function GetPeerIPAddr(aSocket: TSocket): string;
function GetPeerPort(aSocket: TSocket): string;
function GetBlocking: Boolean;
procedure SetBlocking(flag: Boolean);
property Text: string read GetText write SetText;
property Peek: string read PeekData;
property OOB: string read GetTextOOB write SetTextOOB;
property SocketNumber: TSocket read FSocket write FSocket;
property MasterSocket: TSocket read FMSocket write FMSocket;
published
property IPAddr: string read FIPAddr write FIPAddr;
property Port: string read FPort write FPort;
property NonBlocking: Boolean read GetBlocking write SetBlocking default True;
property Timeout: integer read FTimeout write FTimeout default 30;
property OnDataAvailable: TDataAvailable read FDataAvailable
write FDataAvailable;
property OnSessionClosed: TSessionClosed read FSessionClosed
write FSessionClosed;
property OnSessionAvailable: TSessionAvailable read FSessionAvailable
write FSessionAvailable;
property OnSessionConnected: TSessionConnected read FSessionConnected
write FSessionConnected;
property OnErrorOccurred: TErrorOccurred read FErrorOccurred
write FErrorOccurred;
end;
procedure Register;
implementation
{ Function declarations for window's sockets (winsock) This is a complete
set of function declarations for winsock, not all functions are called
from this component. }
function accept(s: TSocket; var addr: sockaddr_in; var addrlen: integer) : TSocket;
far; external 'WINSOCK';
function bind(s: TSocket; var addr: sockaddr_in; namelen: integer) : integer;
far; external 'WINSOCK';
function closesocket(s: TSocket) : integer;
far; external 'WINSOCK';
function connect(s: TSocket; var name: sockaddr_in; namelen: integer) : integer;
far; external 'WINSOCK';
function ioctlsocket(s: TSocket; cmd: longint; var argp: longint) : integer;
far; external 'WINSOCK';
function getpeername(s: TSocket; var name: sockaddr_in; var namelen: integer) :
integer; far; external 'WINSOCK';
function getsockname(s: TSocket; var name: sockaddr_in; var namelen: integer) :
integer; far; external 'WINSOCK';
function getsockopt(s: TSocket; level: integer; optname: integer;
optval: PChar; var optlen: integer) : integer; far; external 'WINSOCK';
function htonl(hostlong: u_long) : u_long; far; external 'WINSOCK';
function htons(hostshort: u_short) : u_short; far; external 'WINSOCK';
function inet_addr(cp: PChar) : u_long; far; external 'WINSOCK';
function inet_ntoa(sin: in_addr) : PChar; far; external 'WINSOCK';
function listen(s: TSocket; backlog: integer) : integer;
far; external 'WINSOCK';
function ntohl(netlong: u_long) : u_long; far; external 'WINSOCK';
function ntohs(netshort: u_short) : u_short; far; external 'WINSOCK';
function recv(s: TSocket; buf: PChar; len: integer; flags: integer) : integer;
far; external 'WINSOCK';
function recvfrom(s: TSocket; buf: PChar; len: integer; flags: integer;
var from: sockaddr_in; var fromlen: integer) : integer; far; external 'WINSOCK';
function send(s: TSocket; buf: PChar; len: integer; flags: integer) : integer;
far; external 'WINSOCK';
function sendto(s: TSocket; buf: PChar; len: integer; flags: integer;
var saddrto: sockaddr_in; tolen: integer) : integer; far; external 'WINSOCK';
function setsockopt(s: TSocket; level: integer; optname: integer; optval: PChar;
optlen: integer) : integer; far; external 'WINSOCK';
function shutdown(s: TSocket; how: integer) : integer; far; external 'WINSOCK';
function socket(af: integer; stype: integer; protocol: integer) : TSocket;
far; external 'WINSOCK';
function gethostbyaddr(addr: PChar; len: integer; stype: integer) : phostent;
far; external 'WINSOCK';
function gethostbyname(name: PChar) : phostent; far; external 'WINSOCK';
function gethostname(name: PChar) : integer; far; external 'WINSOCK';
function getservbyport(port: integer; proto: PChar) : pservent;
far; external 'WINSOCK';
function getservbyname(name: PChar; proto: PChar) : pservent;
far; external 'WINSOCK';
function getprotobynumber(proto: integer) : pprotoent; far; external 'WINSOCK';
function getprotobyname(name: PChar) : pprotoent; far; external 'WINSOCK';
{ Winsock extensions to Berkeley Sockets }
function WSAStartup(wVersionRequired: word; var lpWSAData: WSADATA) : integer;
far; external 'WINSOCK';
function WSACleanup : integer; far; external 'WINSOCK';
procedure WSASetLastError(iError: integer); far; external 'WINSOCK';
function WSAGetLastError : integer; far; external 'WINSOCK';
function WSAIsBlocking : Boolean; far; external 'WINSOCK';
function WSASetBlockingHook : integer; far; external 'WINSOCK';
function WSACancelBlockingCall : integer; far; external 'WINSOCK';
function WSAAsyncGetServByName(handle: HWND; wMsg: u_int; name: pChar;
proto: PChar; buf: PChar; buflen: integer) : THandle; far; external 'WINSOCK';
function WSAAsyncGetServByPort(handle: HWND; wMsg: u_int; port: integer;
proto: PChar; buf: PChar; buflen: integer) : THandle; far; external 'WINSOCK';
function WSAAsyncGetProtoByName(handle: HWND; wMsg: u_int; name: PChar;
buf: PChar; buflen: integer) : THandle; far; external 'WINSOCK';
function WSAAsyncGetProtoByNumber(handle: HWND; wMsg: u_int; number: integer;
buf: PChar; buflen: integer) : THandle; far; external 'WINSOCK';
function WSAAsyncGetHostByName(handle: HWND; wMsg: u_int; name: PChar;
buf: PChar; buflen: integer) : THandle; far; external 'WINSOCK';
function WSAAsyncGetHostByAddr(handle: HWND; wMsg: u_int; addr: PChar;
len: integer; atype: integer; buf: PChar; buflen: integer) : THandle;
far; external 'WINSOCK';
function WSACancelAsyncRequest(handle: THandle) :THandle;
far; external 'WINSOCK';
function WSAAsyncSelect(s: TSocket; handle: HWND; wMsg: u_int; lEvent: longint)
: integer; far; external 'WINSOCK';
procedure Register;
begin
RegisterComponents('Samples', [TSockets]);
end;
constructor TSockets.Create(AOwner: TComponent);
var
iStatus: integer;
begin
inherited Create(AOwner);
FMode := 1;
FTimeout := 30;
FSocket := INVALID_SOCKET;
FMSocket := INVALID_SOCKET;
iStatus := WSAStartup($101,initdata);
if iStatus <> 0 then
SocketError('Constructor (WSAStartup)');
Invalidate;
end;
destructor TSockets.Destroy;
var
iStatus: integer;
begin
iStatus := WSACleanup;
if iStatus < 0 then
SocketError('Destructor (WSACleanup)');
inherited Destroy;
end;
procedure TSockets.TWMPaint(var msg: TWMPaint);
var
icon: HIcon;
dc: HDC;
begin
if csDesigning in ComponentState then
begin
icon := LoadIcon(HInstance,MAKEINTRESOURCE('TSOCKETS'));
dc := GetDC(Handle);
Width := 32;
Height := 32;
DrawIcon(dc,0,0,icon);
ReleaseDC(Handle,dc);
FreeResource(icon);
end;
ValidateRect(Handle,nil);
end;
function TSockets.GetBlocking: Boolean;
begin
if FMode = 1 then
Result := True
else
Result := False;
end;
procedure TSockets.SetBlocking(flag: Boolean);
begin
if flag then
FMode := 1
else
FMode := 0;
end;
procedure TSockets.SetText(Text: string);
var
BytesLeft, BytesSent: integer;
szBigBuff: array[0..256] of char;
pBuf: PChar;
begin
StrPCopy(szBigBuff,Text);
pBuf := @szBigBuff[0];
BytesLeft := Length(Text);
while BytesLeft > 0 do
begin
if FMode = 0 then
SetTimeout;
BytesSent := send(FSocket,pBuf,BytesLeft,0);
if FMode = 0 then
ResetTimeout;
if BytesSent < 0 then
SocketError('SetText (Send)');
BytesLeft := BytesLeft - BytesSent;
pBuf := pBuf + BytesSent;
end;
end;
function TSockets.GetText: string;
var
len: integer;
BigBuff: string;
szBigBuff: array[0..256] of char absolute BigBuff;
begin
if FSocket <> INVALID_SOCKET then
begin
if FMode = 0 then
SetTimeout;
len := recv(FSocket,@szBigBuff[1],255,0);
if FMode = 0 then
ResetTimeout;
if len < 0 then
SocketError('GetText (Recv)');
szBigBuff[0] := chr(len);
Result := BigBuff;
end
else Result := '';
end;
procedure TSockets.SetTextOOB(Text: string);
var
BytesLeft, BytesSent: integer;
szBigBuff: array[0..256] of char;
pBuf: PChar;
begin
StrPCopy(szBigBuff,Text);
pBuf := @szBigBuff[0];
BytesLeft := Length(Text);
while BytesLeft > 0 do
begin
if FMode = 0 then
SetTimeout;
BytesSent := send(FSocket,pBuf,BytesLeft,MSG_OOB);
if FMode = 0 then
ResetTimeout;
if BytesSent < 0 then
SocketError('SetText (Send)');
BytesLeft := BytesLeft - BytesSent;
pBuf := pBuf + BytesSent;
end;
end;
function TSockets.GetTextOOB: string;
var
len: integer;
BigBuff: string;
szBigBuff: array[0..256] of char absolute BigBuff;
begin
if FSocket <> INVALID_SOCKET then
begin
if FMode = 0 then
SetTimeout;
len := recv(FSocket,@szBigBuff[1],255,MSG_OOB);
if FMode = 0 then
ResetTimeout;
if len < 0 then
SocketError('GetText (Recv)');
szBigBuff[0] := chr(len);
Result := BigBuff;
end
else Result := '';
end;
function TSockets.PeekData: string;
var
len: integer;
BigBuff: string;
szBigBuff: array[0..256] of char absolute BigBuff;
begin
if FSocket <> INVALID_SOCKET then
begin
if FMode = 0 then
SetTimeout;
len := recv(FSocket,@szBigBuff[1],255,MSG_PEEK);
if FMode = 0 then
ResetTimeout;
if len < 0 then
SocketError('PeekData (Peek)');
szBigBuff[0] := chr(len);
Result := BigBuff;
end
else Result := '';
end;
function TSockets.GetPort(aSocket: TSocket): string;
var
addr: sockaddr_in;
addrlen: integer;
begin
addrlen := sizeof(addr);
getsockname(aSocket,addr,addrlen);
Result := IntToStr(ntohs(addr.sin_port));
end;
function TSockets.GetIPAddr(aSocket: TSocket): string;
var
addr: sockaddr_in;
addrlen: integer;
szIPAddr: PChar;
begin
addrlen := sizeof(addr);
getsockname(aSocket,addr,addrlen);
szIPAddr := inet_ntoa(addr.sin_addr);
Result := StrPas(szIPAddr);
end;
function TSockets.GetPeerPort(aSocket: TSocket): string;
var
addr: sockaddr_in;
addrlen: integer;
begin
addrlen := sizeof(addr);
getpeername(aSocket,addr,addrlen);
Result := IntToStr(ntohs(addr.sin_port));
end;
function TSockets.GetPeerIPAddr(aSocket: TSocket): string;
var
addr: sockaddr_in;
addrlen: integer;
szIPAddr: PChar;
begin
addrlen := sizeof(addr);
getpeername(aSocket,addr,addrlen);
szIPAddr := inet_ntoa(addr.sin_addr);
Result := StrPas(szIPAddr);
end;
function TSockets.SReceive(aSocket: TSocket; szBuff: PChar; var rlen: integer) : integer;
begin
if FSocket <> INVALID_SOCKET then
begin
if FMode = 0 then
SetTimeout;
Result := recv(aSocket,szBuff,rlen,0);
if FMode = 0 then
ResetTimeout;
if rlen < 0 then
SocketError('SReceive');
end
else Result := -1;
end;
function TSockets.SSend(aSocket: TSocket; szBuff: PChar; var slen: integer): integer;
begin
if FMode = 0 then
SetTimeout;
slen := send(aSocket,szBuff,slen,0);
if FMode = 0 then
ResetTimeout;
if slen < 0 then
SocketError('SSend');
Result := slen;
end;
procedure TSockets.WMASyncSelect(var msg: TMessage);
begin
case LoWord(msg.lParam) of
FD_READ:
begin
if Assigned(FDataAvailable) then
FDataAvailable(Self,msg.wParam);
end;
FD_CLOSE:
begin
if Assigned(FSessionClosed) then
FSessionClosed(Self,msg.wParam);
end;
FD_ACCEPT:
begin
if Assigned(FSessionAvailable) then
FSessionAvailable(Self,msg.wParam);
end;
FD_CONNECT:
begin
if Assigned(FSessionConnected) then
FSessionConnected(Self,msg.wParam);
end;
end;
end;
procedure TSockets.WMTimer(var msg: TMessage);
var
szErrMsg: array[0..255] of char;
begin
KillTimer(Handle,10);
if WSAIsBlocking then
begin
WSACancelBlockingCall;
if Assigned(FErrorOccurred) then
FErrorOccurred(Self,WSAETIMEDOUT,'Blocking call timed out')
else
begin
StrPCopy(szErrMsg,'Error ' + IntToStr(WSAETIMEDOUT) + #13#10 +
'Blocking call timed out');
Application.MessageBox(szErrMsg, 'WINSOCK CALL CANCELED', mb_OKCancel +
mb_DefButton1);
end;
end;
end;
procedure TSockets.SConnect;
var
iStatus: integer;
szTcp: PChar;
szPort: array[0..31] of char;
szData: array[0..256] of char;
begin
if FPort = '' then
begin
Application.MessageBox('No Port Specified', 'WINSOCK ERROR', mb_OKCancel +
mb_DefButton1);
exit;
end;
if FIPAddr = '' then
begin
Application.MessageBox('No IP Address Specified', 'WINSOCK ERROR', mb_OKCancel +
mb_DefButton1);
exit;
end;
sin.sin_family := AF_INET;
StrPCopy(szPort,FPort);
szTcp := 'tcp';
Pse := getservbyname(szPort,szTcp);
if Pse = nil then
sin.sin_port := htons(StrToInt(StrPas(szPort)))
else sin.sin_port := Pse^.s_port;
StrPCopy(szData,FIPAddr);
sin.sin_addr.s_addr := inet_addr(szData);
if sin.sin_addr.s_addr = INADDR_NONE then
begin
Phe := gethostbyname(szData);
if Phe = nil then
begin
StrPCopy(szData,'Cannot convert host address');
Application.MessageBox(szData, 'WINSOCK ERROR', mb_OKCancel +
mb_DefButton1);
exit;
end;
sin.sin_addr := Phe^.h_addr^^;
end;
Ppe := getprotobyname(szTcp);
FSocket := socket(PF_INET,SOCK_STREAM,Ppe^.p_proto);
if FSocket < 0 then
SocketError('SConnect (socket)');
if FMode = 1 then
begin
iStatus := WSAASyncSelect(FSocket,Handle,WM_ASYNCSELECT,
FD_READ or FD_CLOSE or FD_CONNECT);
if iStatus <> 0 then
SocketError('WSAAsyncSelect');
end
else
iStatus := ioctlsocket(FSocket,FIONBIO,FMode);
if FMode = 0 then
SetTimeout;
iStatus := connect(FSocket,sin,sizeof(sin));
if FMode = 0 then
ResetTimeout;
if iStatus <> 0 then
begin
iStatus := WSAGetLastError;
if iStatus <> WSAEWOULDBLOCK then
SocketError('SConnect');
end;
end;
procedure TSockets.SListen;
var
iStatus: integer;
szTcp: PChar;
szPort: array[0..31] of char;
szData: array[0..256] of char;
begin
if FPort = '' then
begin
Application.MessageBox('No Port Specified', 'WINSOCK ERROR', mb_OKCancel +
mb_DefButton1);
exit;
end;
sin.sin_family := AF_INET;
sin.sin_addr.s_addr := INADDR_ANY;
szTcp := 'tcp';
StrPCopy(szPort,FPort);
Pse := getservbyname(szPort,szTcp);
if Pse = nil then
sin.sin_port := htons(StrToInt(StrPas(szPort)))
else sin.sin_port := Pse^.s_port;
Ppe := getprotobyname(szTcp);
FMSocket := socket(PF_INET,SOCK_STREAM,Ppe^.p_proto);
if FMSocket < 0 then
SocketError('socket');
iStatus := bind(FMSocket, sin, sizeof(sin));
if iStatus <> 0 then
SocketError('Bind');
iStatus := listen(FMSocket,5);
if iStatus <> 0 then
SocketError('Listen');
if FMode = 1 then
begin
iStatus := WSAASyncSelect(FMSocket,Handle,WM_ASYNCSELECT,
FD_READ or FD_ACCEPT or FD_CLOSE);
if iStatus <> 0 then
SocketError('WSAASyncSelect');
end
else ioctlsocket(FMSocket,FIONBIO,FMode);
end;
procedure TSockets.SCancelListen;
var
iStatus: integer;
begin
if FMode = 1 then
WSAASyncSelect(FMSocket,Handle,WM_ASYNCSELECT,0);
shutdown(FMSocket,2);
iStatus := closesocket(FMSocket);
if iStatus <> 0 then
SocketError('CancelListen (closesocket)');
FMSocket := 0;
end;
function TSockets.SAccept: TSocket;
var
iStatus: integer;
len: integer;
begin
len := sizeof(sin);
if FMode = 0 then
SetTimeout;
FSocket := accept(FMSocket,sin,len);
if FMode = 0 then
begin
ResetTimeout;
ioctlsocket(FSocket,FIONBIO,FMode);
end;
if FMSocket < 0 then
SocketError('Accept');
Result := FSocket;
end;
procedure TSockets.SClose;
var
iStatus: integer;
lin: linger;
linx: array[0..3] of char absolute lin;
begin
if FMode = 1 then
WSAASyncSelect(FSocket,Handle,WM_ASYNCSELECT,0);
if WSAIsBlocking then
WSACancelBlockingCall;
shutdown(FSocket,2);
lin.l_onoff := 1;
lin.l_linger := 0;
setsockopt(FSocket,SOL_SOCKET,SO_LINGER,linx,sizeof(lin));
iStatus := closesocket(FSocket);
if iStatus <> 0 then
SocketError('Disconnect (closesocket)');
FSocket := INVALID_SOCKET;
end;
procedure TSockets.SocketError(sockfunc: string);
var
szLine: array[0..255] of char;
error: integer;
line, ErrMsg: string;
begin
error := WSAGetLastError;
ErrMsg := SocketErrorDesc(error);
line := 'Error '+ IntToStr(error) + ' in function ' + sockfunc +
#13#10 + ErrMsg;
if Assigned(FErrorOccurred) then
FErrorOccurred(Self,error,ErrMsg)
else
begin
StrPCopy(szLine,line);
Application.MessageBox(szLine, 'WINSOCK ERROR', mb_OKCancel +
mb_DefButton1);
halt;
end;
end;
function TSockets.SocketErrorDesc(error: integer) : string;
begin
case error of
WSAEINTR:
SocketErrorDesc := 'Interrupted system call';
WSAEBADF:
SocketErrorDesc := 'Bad file number';
WSAEACCES:
SocketErrorDesc := 'Permission denied';
WSAEFAULT:
SocketErrorDesc := 'Bad address';
WSAEINVAL:
SocketErrorDesc := 'Invalid argument';
WSAEMFILE:
SocketErrorDesc := 'Too many open files';
WSAEWOULDBLOCK:
SocketErrorDesc := 'Operation would block';
WSAEINPROGRESS:
SocketErrorDesc := 'Operation now in progress';
WSAEALREADY:
SocketErrorDesc := 'Operation already in progress';
WSAENOTSOCK:
SocketErrorDesc := 'Socket operation on non-socket';
WSAEDESTADDRREQ:
SocketErrorDesc := 'Destination address required';
WSAEMSGSIZE:
SocketErrorDesc := 'Message too long';
WSAEPROTOTYPE:
SocketErrorDesc := 'Protocol wrong type for socket';
WSAENOPROTOOPT:
SocketErrorDesc := 'Protocol not available';
WSAEPROTONOSUPPORT:
SocketErrorDesc := 'Protocol not supported';
WSAESOCKTNOSUPPORT:
SocketErrorDesc := 'Socket type not supported';
WSAEOPNOTSUPP:
SocketErrorDesc := 'Operation not supported on socket';
WSAEPFNOSUPPORT:
SocketErrorDesc := 'Protocol family not supported';
WSAEAFNOSUPPORT:
SocketErrorDesc := 'Address family not supported by protocol family';
WSAEADDRINUSE:
SocketErrorDesc := 'Address already in use';
WSAEADDRNOTAVAIL:
SocketErrorDesc := 'Can''t assign requested address';
WSAENETDOWN:
SocketErrorDesc := 'Network is down';
WSAENETUNREACH:
SocketErrorDesc := 'Network is unreachable';
WSAENETRESET:
SocketErrorDesc := 'Network dropped connection on reset';
WSAECONNABORTED:
SocketErrorDesc := 'Software caused connection abort';
WSAECONNRESET:
SocketErrorDesc := 'Connection reset by peer';
WSAENOBUFS:
SocketErrorDesc := 'No buffer space available';
WSAEISCONN:
SocketErrorDesc := 'Socket is already connected';
WSAENOTCONN:
SocketErrorDesc := 'Socket is not connected';
WSAESHUTDOWN:
SocketErrorDesc := 'Can''t send after socket shutdown';
WSAETOOMANYREFS:
SocketErrorDesc := 'Too many references: can''t splice';
WSAETIMEDOUT:
SocketErrorDesc := 'Connection timed out';
WSAECONNREFUSED:
SocketErrorDesc := 'Connection refused';
WSAELOOP:
SocketErrorDesc := 'Too many levels of symbolic links';
WSAENAMETOOLONG:
SocketErrorDesc := 'File name too long';
WSAEHOSTDOWN:
SocketErrorDesc := 'Host is down';
WSAEHOSTUNREACH:
SocketErrorDesc := 'No route to host';
WSAENOTEMPTY:
SocketErrorDesc := 'Directory not empty';
WSAEPROCLIM:
SocketErrorDesc := 'Too many processes';
WSAEUSERS:
SocketErrorDesc := 'Too many users';
WSAEDQUOT:
SocketErrorDesc := 'Disc quota exceeded';
WSAESTALE:
SocketErrorDesc := 'Stale NFS file handle';
WSAEREMOTE:
SocketErrorDesc := 'Too many levels of remote in path';
WSASYSNOTREADY:
SocketErrorDesc := 'Network sub-system is unusable';
WSAVERNOTSUPPORTED:
SocketErrorDesc := 'WinSock DLL cannot support this application';
WSANOTINITIALISED:
SocketErrorDesc := 'WinSock not initialized';
WSAHOST_NOT_FOUND:
SocketErrorDesc := 'Host not found';
WSATRY_AGAIN:
SocketErrorDesc := 'Non-authoritative host not found';
WSANO_RECOVERY:
SocketErrorDesc := 'Non-recoverable error';
WSANO_DATA:
SocketErrorDesc := 'No Data';
else SocketErrorDesc := 'Not a WinSock error';
end;
end;
procedure TSockets.SetTimeout;
begin
if FTimeout > 0 then
SetTimer(Handle,10,FTimeout*1000,nil);
end;
procedure TSockets.ResetTimeout;
begin
if FTimeout > 0 then
KillTimer(Handle,10);
end;
end.